package one.stand.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.vioao.wechat.utils.signature.DigestUtil;
import com.github.wxpay.sdk.WXPayUtil;
import com.jmp.autocofiguration.web.interceptor.SecurityAuthCheck;
import com.jmp.base.dto.*;
import com.jmp.feign.AccountFeign;
import com.jmp.feign.SecurityFeign;
import com.jmp.feign.WechatFeign;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import one.stand.advice.ResultEnum;
import one.stand.dto.*;
import one.stand.enums.LoginEnum;
import one.stand.mapper.TrainCountMapper;
import one.stand.mapper.UserSignMapper;
import one.stand.model.*;
import one.stand.service.UserSignService;
import one.stand.service.sys.SysDictValueService;
import one.stand.service.user.UserAdminService;
import one.stand.util.*;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Api(description = "签到管理")
@RestController
@RequestMapping("/sign")
@Slf4j
public class SignController {
    private String map_api_translate = "https://apis.map.qq.com/ws/coord/v1/translate?" +
            "&key=A6UBZ-5ROKU-H3NVL-4BI2V-Z3IHZ-W2F5X" +
            "&type=5" +
            "&locations=";
    //29.204638,120.248306 全景红木智慧展厅
    //29.120074,120.224547 花园红木家具城
    private String map_api_distance = "https://apis.map.qq.com/ws/distance/v1/?mode=walking" +
            "&key=A6UBZ-5ROKU-H3NVL-4BI2V-Z3IHZ-W2F5X" +
            "&from=29.120074,120.224547" +
            "&to=";

    @Autowired
    private SecurityFeign securityFeign;
    @Autowired
    private WechatFeign wechatFeign;
    @Autowired
    private AccountFeign accountFeign;

    @Autowired
    private UserSignService userSignService;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private SysDictValueService sysDictValueService;
    @Autowired
    private UserAdminService userAdminService;
    @Autowired
    private UserSignMapper userSignMapper;
    @Autowired
    private TrainCountMapper trainCountMapper;

    @ApiOperation("签到")
    @PostMapping("/save")
    @SecurityAuthCheck
    public ResultModel save(@RequestBody UserSignSaveRequest request) {
        RequestContext.User contextUser = RequestContextHolder.getRequestContext().getUser();

        Integer ifSign = userSignService.checkSignByUserId(contextUser.getUserId());
        if (ifSign < 1) {
            userSignService.save(contextUser.getUserId()
                    , request.getArea()
                    , request.getBuild()
                    , request.getStreet()
                    , request.getNum()
                    , request.getPosition()
            );
        }
        return ResultModel.success();
    }

    @ApiOperation("查询， TOP50")
    @PostMapping("/query")
    @SecurityAuthCheck
    public ResultModel<UserSignQueryResponse> query() {
        RequestContext.User contextUser = RequestContextHolder.getRequestContext().getUser();

        UserSignQueryResponse response;
        Integer ifSign = userSignService.checkSignByUserId(contextUser.getUserId());
        List<UserSign> userSigns = userSignService.userSignList();

        List<UserSignQueryResponse.UserSignVo> userSignList = ConvertUtils.list(userSigns, userSign -> {
            UserDto user = userAdminService.get(userSign.getUserId());
            return UserSignQueryResponse.UserSignVo.builder()
                    .userId(userSign.getUserId())
                    .addr(userSign.getArea() + userSign.getBuild() + userSign.getStreet() + userSign.getNum())
                    .createTime(DateUtil.format(DateUtil.MMDDHHSS, userSign.getCreateTime()))
                    .position(userSign.getPosition())
                    .nickeName(user.getName())
                    .avatarUrl(user.getUserImg())
                    .build();
        });
        String message = "";
        if (ifSign > 0) {
            message = "您已完成学习，欢迎您再次学习！";
        } else {
            message = "本学习视频可进行暂停、播放、全屏等操作，不可进行快进操作。";
        }
        response = UserSignQueryResponse.builder()
                .ifSign(ifSign > 0 ? 1 : 0)
                .message(message)
                .userSignList(userSignList)
                .build();

        return ResultModel.success(response);
    }

    @PostMapping("/count")
    public ResultModel<SignCountResponse> count() {
        TrainCount trainCount = trainCountMapper.selectByPrimaryKey(1);
        List<UserSign> userSigns = userSignMapper.selectList();

        List<SignCountResponse.Sign> userSignList = ConvertUtils.list(userSigns, userSign -> {
            UserDto user = userAdminService.get(userSign.getUserId());
            return SignCountResponse.Sign.builder()
                    .addr(userSign.getArea() + userSign.getBuild() + userSign.getStreet() + userSign.getNum())
                    .createTime(DateUtil.format(DateUtil.MMDDHHSS, userSign.getCreateTime()))
                    .position(userSign.getPosition())
                    .nickeName(user.getName())
                    .avatarUrl(user.getUserImg())
                    .build();
        });
        SignCountResponse response = SignCountResponse.builder()
                .visitCount(trainCount.getCountNum())
                .signCount(userSignList.size())
                .list(userSignList)
                .build();

        return ResultModel.success(response);
    }

    @ApiOperation("配置")
    @PostMapping("/config")
    public ResultModel<SignConfigResponse> config(@RequestBody SignConfigRequest signConfigRequest) {

        ResultModel<AccountResponse> responseResultModel = accountFeign.getCompanyIdDefaultIfNull(AccountCompanyIdRequest.builder()
                .companyId(null)
                .loginEnum(LoginEnum.GZH)
                .build());
        AssertUtil.isTrue(responseResultModel);
        String appid = responseResultModel.getData().getAppId();
        String appSecret = responseResultModel.getData().getAppSecret();
        ResultModel<WechatTokenResponse> tokenResponseResultModel = wechatFeign.ticket(WechatTokenRequest.builder().appId(appid).appSecret(appSecret).build());
        AssertUtil.isTrue(tokenResponseResultModel);
        String ticket = tokenResponseResultModel.getData().getToken();
        String noncestr = WXPayUtil.generateNonceStr();
        String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
        String url = signConfigRequest.getUrl();
        String string1 = "jsapi_ticket=" + ticket + "&noncestr=" + noncestr + "&timestamp=" + timestamp + "&url=" + url;
        String signature = DigestUtil.sha1Hex(string1);
        log.info("{} {} {} {}", ticket, noncestr, timestamp, url);
        log.info("{} {}", string1, signature);

        SignConfigResponse response = SignConfigResponse.builder()
                .appId(appid)
                .nonceStr(noncestr)
                .timestamp(timestamp)
                .signature(signature)
                .build();
        return ResultModel.success(response);
    }

    @ApiOperation("登录")
    @PostMapping("/login")
    public ResultModel<SignLoginResponse> login(@RequestBody SignLoginRequest request) {


        SecurityLoginGzhApiRequest wxRequest = SecurityLoginGzhApiRequest.builder()
                .code(request.getCode())
                .loginEnum(LoginEnum.H5_LEAD)
                .build();
        ResultModel<SecurityLoginGzhApiResponse> result = securityFeign.loginGzhApiWx(wxRequest);
        AssertUtil.isTrue(result);

        boolean isMapCheck = true;
        String mapCheckMessage = null;
        Integer ifSign = userSignService.checkSignByUserId(result.getData().getUserId());
        if (ifSign <= 0) {
            SysDictValue mapConfig = sysDictValueService.get(SysDictValueService.Type.SIGN, SysDictValueService.TypeName.SIGN);
            if (Objects.nonNull(mapConfig)) {
                BigDecimal distance = getDistance(request.getLatLng());
                log.info("distance: {} {}", request.getLatLng(), distance);
                isMapCheck = Objects.nonNull(distance) && distance.compareTo(new BigDecimal(mapConfig.getValue())) <= 0;
                mapCheckMessage = String.format("系统检测到您好像不在花园红木家具城%s公里范围内，无法参与学习！", Integer.parseInt(mapConfig.getValue()) / 1000);
            }
        }

        SignLoginResponse loginResponse = SignLoginResponse.builder()
                .token(result.getData().getToken())
                .mapCheck(BooleanUtils.toInteger(isMapCheck))
                .mapCheckMessage(mapCheckMessage)
                .build();
        return ResultModel.success(loginResponse);
    }

    private BigDecimal getDistance(String latLng) {
        if (StringUtils.isBlank(latLng)) return null;

        String key = "distance:" + latLng;
        BigDecimal distance = redisUtil.get(key);
        if (Objects.nonNull(distance)) {
            return distance;
        }

        try {
//            String latLngQQ = getLatLngQQ(latLng);
            String jsonString = HttpUtil2.get(map_api_distance + latLng);
            log.info("map api distance:{}", jsonString);
            JSONObject jsonObject = JSON.parseObject(jsonString);
            int status = jsonObject.getInteger("status");
            AssertUtil.isTrue(status == 0, ResultEnum.PARAM_CHECK, "");

            JSONObject latLngObject = jsonObject.getJSONObject("result").getJSONArray("elements").getJSONObject(0);
            distance = latLngObject.getBigDecimal("distance");

            if (Objects.nonNull(distance)) {
                redisUtil.set(key, distance, 30, TimeUnit.DAYS);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return distance;
    }

    private String getLatLngQQ(String latLng) throws IOException {

        String jsonString = HttpUtil2.get(map_api_translate + latLng);
        log.info("map api translate:{}", jsonString);
        JSONObject jsonObject = JSON.parseObject(jsonString);
        int status = jsonObject.getInteger("status");
        AssertUtil.isTrue(status == 0, ResultEnum.PARAM_CHECK, "");

        JSONObject latLngObject = jsonObject.getJSONArray("locations").getJSONObject(0);
        return latLngObject.get("lat") + "," + latLngObject.get("lng");
    }
}
